/**
 * Create by mzq
 * Description: index
 * Date: 2024/9/25 11:26
 * Update: 2024/9/25 11:26
 */

import bleUtils from "./bleUtils";

const littleEndianUtils = require("./little_endian_utils");
import {BLE_PACKET_SIZE} from "../../public";

import store from '../../store/index';

const CONTROL_OPCODES = {
    CREATE: 0x01,
    SET_PRN: 0x02,
    CALCULATE_CHECKSUM: 0x03,
    EXECUTE: 0x04,
    SELECT: 0x06,
    RESPONSE_CODE: 0x60,
};

const CONTROL_PARAMETERS = {
    COMMAND_OBJECT: 0x01,
    DATA_OBJECT: 0x02,
    // size: Object size in little endian, set by caller.
    // vale: Number of packets to be sent before receiving a PRN, set by caller. Default == 0.
};

/**
 * 将16进制字符串转换为ArrayBuffer
 * @param hex
 * @returns {ArrayBufferLike}
 */
export function bufferFromHex(hex) {
    const typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {
        return parseInt(h, 16)
    }));
    return typedArray.buffer
}

/**
 * 将二进制数据转换为十六进制字符串
 * @param buffer
 * @returns {string}
 */
export function ab2hex(buffer) {
    const hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function (bit) {
            return ('00' + bit.toString(16)).slice(-2)
        }
    );
    return hexArr.join('');
}

/**
 * 向90001写入数据
 * @param device
 * @param dataView
 * @param buffer
 * @param type
 * @returns {*}
 */
export function bleWriteTo90001(device, dataView, buffer, type) {
    console.log("90001发送的数据：", device)
    store.commit("setSendType", type)
    console.log("buffer", buffer)
    console.log("store下面的type", store.state.sendType)
    for (let i = 0; i < dataView.byteLength; i++) {
        console.log("0x" + dataView.getUint8(i).toString(16))
    }



    return bleUtils.writeBLECharacteristicValue({
        deviceId: device.deviceId,
        serviceId: device.serverFE59["uuid"],
        characteristicId: device.characteristic90001["uuid"],
        value: buffer
    })
}

/**
 * 向90003写入数据
 * @param device
 * @param dataView
 * @param buffer
 * @returns {*}
 */
export function bleWriteTo90003(device, dataView, buffer) {
    console.log("90003发送的数据：")
    for (let i = 0; i < dataView.byteLength; i++) {
        console.log("0x" + dataView.getUint8(i).toString(16))
    }

    return bleUtils.writeBLECharacteristicValue({
        deviceId: device.deviceId,
        serviceId: device.serverFE59["uuid"],
        characteristicId: device.characteristic90003["uuid"],
        value: buffer
    })
}


/**
 * 发送PRN
 * @param device
 */
export function sendPRN(device) {
    console.log("prn", device)
    const buffer = new ArrayBuffer(3);
    const dataView = new DataView(buffer);
    //写入通道指令
    dataView.setUint8(0, CONTROL_OPCODES.SET_PRN)
    dataView.setUint8(1, 0x00)
    dataView.setUint8(2, 0x00)
    bleWriteTo90001(device, dataView, buffer, 4)
}

/**
 * 发送EXECUTE
 * @param device
 */
export function sendEXECUTE(device) {
    console.log("进入了execute", device)
    const buffer = new ArrayBuffer(1);
    const dataView = new DataView(buffer);
    //写入通道指令
    dataView.setUint8(0, CONTROL_OPCODES.EXECUTE)
    bleWriteTo90001(device, dataView, buffer, 5)
}

export function sendCreate(device) {
    console.log("进入了sendcreate", device)
    const buffer = new ArrayBuffer(6);
    const dataView = new DataView(buffer);
    //写入通道指令
    dataView.setUint8(0, CONTROL_OPCODES.CREATE)
    dataView.setUint8(1, CONTROL_PARAMETERS.COMMAND_OBJECT)
    dataView.setUint8(2, 0x8d)
    dataView.setUint8(3, 0x0)
    dataView.setUint8(4, 0x0)
    dataView.setUint8(5, 0x0)
    return bleWriteTo90001(device, dataView, buffer, 7)
}


/**
 * 解析响应数据
 * @param response
 * @returns {{data: ({offset: *, crc32: *}|{offset: *, maximumSize: *, crc32: *}), resultCode: number, responseOpCode: number, responseCode: number}}
 */
export function parseResponse(response) {
    const BASE_POS = 3;

    const CONTROL_OPCODES = {
        CREATE: 0x01,
        SET_PRN: 0x02,
        CALCULATE_CHECKSUM: 0x03,
        EXECUTE: 0x04,
        SELECT: 0x06,
        RESPONSE_CODE: 0x60,
    };


    const RESULT_CODES = {
        INVALID_CODE: 0x00,
        SUCCESS: 0x01,
        OPCODE_NOT_SUPPORTED: 0x02,
        INVALID_PARAMETER: 0x03,
        INSUFFICIENT_RESOURCES: 0x04,
        INVALID_OBJECT: 0x05,
        UNSUPPORTED_TYPE: 0x07,
        OPERATION_NOT_PERMITTED: 0x08,
        OPERATION_FAILED: 0x0A,
    };

    const CALCULATE_CHECKSUM_RESPONSE_FIELD = {
        OFFSET: BASE_POS + 0,
        CRC32: BASE_POS + 4,
    };

    const SELECT_RESPONSE_FIELD = {
        MAXIMUM_SIZE: BASE_POS + 0,
        OFFSET: BASE_POS + 4,
        CRC32: BASE_POS + 8,
    };

    const reverseLookup = obj => val => {
        for (const k of Object.keys(obj)) {
            if (obj[k] === val) {
                return k;
            }
        }
        return 'UNKNOWN';
    };

    const controlOpCodeToString = reverseLookup(CONTROL_OPCODES);
    const resultCodeToString = reverseLookup(RESULT_CODES);

    var response = new DataView(response);
    const responseCode = response.getUint8(0);
    const responseOpCode = response.getUint8(1);
    const resultCode = response.getUint8(2);
    let responseSpecificData;

    console.log(response + " responseCode:" + responseCode);
    console.log(response + " resultCode:" + resultCode);


    if (responseCode !== CONTROL_OPCODES.RESPONSE_CODE) {
        throw new Error(`Unexpected response code received: ${controlOpCodeToString(responseCode)}.`);
    }
    if (resultCode !== RESULT_CODES.SUCCESS) {
        throw new Error(`Error in result code: ${resultCodeToString(resultCode)}.`);
    }

    switch (responseOpCode) {
        case CONTROL_OPCODES.CREATE:
            break;
        case CONTROL_OPCODES.SET_PRN:
            break;
        case CONTROL_OPCODES.CALCULATE_CHECKSUM:
            responseSpecificData = {
                offset: littleEndianUtils.littleEndianUInt32(response.getUint32(CALCULATE_CHECKSUM_RESPONSE_FIELD.OFFSET)),
                crc32: littleEndianUtils.littleEndianUInt32(response.getUint32(CALCULATE_CHECKSUM_RESPONSE_FIELD.CRC32)),
            };
            break;
        case CONTROL_OPCODES.EXECUTE:
            console.log('04执行');
            break;
        case CONTROL_OPCODES.SELECT:
            responseSpecificData = {
                maximumSize: littleEndianUtils.littleEndianUInt32(response.getUint32(SELECT_RESPONSE_FIELD.MAXIMUM_SIZE)),
                offset: littleEndianUtils.littleEndianUInt32(response.getUint32(SELECT_RESPONSE_FIELD.OFFSET)),
                crc32: littleEndianUtils.littleEndianUInt32(response.getUint32(SELECT_RESPONSE_FIELD.CRC32)),
            };
            break;
        default:
            throw new Error(`Unknwon response op-code received: ${controlOpCodeToString(responseOpCode)}.`);
    }

    return {
        responseCode: responseCode,
        responseOpCode: responseOpCode,
        resultCode: resultCode,
        data: responseSpecificData,
    };
}


export function writeBleBin(device, buffer, offset) {
    wx.hideLoading();

    let start = offset
    let length = buffer.byteLength

    for (; offset < length; offset = offset + BLE_PACKET_SIZE) {
        let step = offset + BLE_PACKET_SIZE > length ? length - offset : BLE_PACKET_SIZE
        let uint8Array = new Uint8Array(buffer, offset, step)
        let hex = ""
        for (let i in uint8Array) {
            let num = uint8Array[i];
            if (num < 16) {
                hex += '0'
            }
            hex += num.toString(16)
        }
        console.log("writeBleDat:" + hex)
        let targetData = bufferFromHex(hex)
        wx.writeBLECharacteristicValue({
            deviceId: device.deviceId,
            serviceId: device.serverFE59["uuid"],
            characteristicId: device.characteristic90002["uuid"],
            value: targetData,
            fail: function (err) {
                offset = offset - BLE_PACKET_SIZE //失败了重写一遍
                console.log('write bin fail', err)
            }
        })

        let percentage = (offset + step) / length
        percentage = (percentage * 100).toFixed(1)

        store.commit("setPercentage", percentage)

        if (offset + step == length) {
            let buffer = new ArrayBuffer(1)
            let dataView = new DataView(buffer)
            //写入通道指令
            dataView.setUint8(0, CONTROL_OPCODES.CALCULATE_CHECKSUM)
            bleWriteTo90001(device, dataView, buffer, 9)
            break
        }

        let timestamp1 = (new Date()).getTime();
        let timestamp2 = (new Date()).getTime();
        while (timestamp2 - timestamp1 < 40) {
            timestamp2 = (new Date()).getTime();
        }

        if (offset - start == 1000) {
            setTimeout((res) => {
                writeBleBin(device, buffer, offset + BLE_PACKET_SIZE)
            }, 10000)
            return;
        }
    }
}


/**
 * 发送创建包 size 代表要发送的字节长度。发送的范围看设备返回的限制，这里是 4096
 * @param device
 * @param size
 */
export function sendCreatePackage(device, size) {
    let buffer = new ArrayBuffer(6)
    let dataView = new DataView(buffer)
    //写入通道指令
    dataView.setUint8(0, CONTROL_OPCODES.CREATE)
    dataView.setUint8(1, CONTROL_PARAMETERS.DATA_OBJECT)
    dataView.setUint8(2, size[0])
    dataView.setUint8(3, size[1])
    dataView.setUint8(4, 0x0)
    dataView.setUint8(5, 0x0)

    // First, select the Command Object. As a response the maximum command size and information whether there is already
    bleWriteTo90001(device, dataView, buffer, 6)
}


export function writeBleDat(device, buffer, offset, thisDevice) {
    uni.showToast({
        title: '即将写入init包'
    });
    let start = offset;
    let length = buffer.byteLength;

    for (; offset < length; offset = offset + BLE_PACKET_SIZE) {
        let step = offset + BLE_PACKET_SIZE > length ? length - offset : BLE_PACKET_SIZE;
        let uint8Array = new Uint8Array(buffer, offset, step);
        let hex = '';
        for (let i in uint8Array) {
            let num = uint8Array[i];
            if (num < 16) {
                hex += '0';
            }
            hex += num.toString(16);
        }

        let targetData = bufferFromHex(hex);
        uni.writeBLECharacteristicValue({
            deviceId: device.deviceId,
            serviceId: device.serverFE59['uuid'],
            characteristicId: device.characteristic90002['uuid'],
            value: targetData,
            fail: function (err) {
                offset = offset - BLE_PACKET_SIZE; //失败了重写一遍
                console.log('write dat fail', err);
            }
        });

        let percentage = (offset + step) / length;
        percentage = (percentage * 100).toFixed(1);
        uni.showLoading({
            title: '写入' + percentage + '%',
            mask: true
        });

        if (offset + step == length) {
            uni.showToast({
                title: '初始化完成'
            });
            console.log('初始化设备完成...');
            var buffer = new ArrayBuffer(1);
            var dataView = new DataView(buffer);
            //写入通道指令
            dataView.setUint8(0, CONTROL_OPCODES.CALCULATE_CHECKSUM);
            console.log('readFile');
            bleWriteTo90001(thisDevice, dataView, buffer, 8);
            break;

            var timestamp1 = new Date().getTime();
            var timestamp2 = new Date().getTime();
            while (timestamp2 - timestamp1 < 40) {
                timestamp2 = new Date().getTime();
            }

            if (offset - start === 1000) {
                setTimeout(function (res) {
                    writeBleDat(device, buffer, offset + BLE_PACKET_SIZE);
                }, 100);
                return;
            }
        }
    }
}


export function formater4length(data) {
    data = data.toString(16)
    if (data.length == 3) {
        data = "0" + data
    } else if (data.length == 2) {
        data = "00" + data
    } else if (data.length == 1) {
        data = "000" + data
    }
    const dataArray = new Array();
    dataArray.push("0x" + data.slice(2))
    dataArray.push("0x" + data.slice(0, 2))
    console.log("hexstr:" + dataArray)
    return dataArray;
}
